from django.utils import simplejson
from gae_db_manager import GaeDbManager
import dlz_config as dc
import model,logging, urllib
from google.appengine.api import urlfetch
from google.appengine.api import memcache
from email_handler import email_notify
from google.appengine.ext import db




        
    
def get_project(project_key):
    '''if the project_key starts with the project number, then it returns the project
    setup this way so that the project_num doesn't need to be fixed length.'''
    project_list = memcache.get('project_list')
    if not project_list:
        q = model.dlz_project_list.all()
        project_list = []
        for r in q:
            project = {}
            for fld in 'project_name project_number client_name'.split():
                project[fld] = getattr(r, fld)
            project_list.append(project)

    for p in project_list:
        project_number = p['project_number']
        if project_key.startswith(project_number):
            return p


    

def project_info_from_project_list(table_name, project_num):
    '''
    update a project info for a table, can be form or test
    '''
    memcache.flush_all()
    table = GaeDbManager(table_name).table
    p = get_project(project_num)
    if p:
        q = table.all().filter('project_number = ', project_num)
        batch = []
        for t in q:
            for fld in 'project_name project_number client_name'.split():
                setattr(t, fld, p[fld])
            batch.append(t)
        db.put(batch)
    else:
        msg = '% is not found in dlz_project_list.' % project_num
        logging.info(msg)
        email_notify('ymeng@dlz.com', 'Missing Project', msg)

def populate_project_info(test_table, form_table):
    '''the testing data have three parts in three different tables:
     1. testing info: compaction_test
     2. form info: compaction_form
     3. project: dlz_project_list
     A procedure is needed to populate the testing table with most up to date data from the three tables.'''
    #get parent id
    memcache.flush_all()
    test = GaeDbManager(test_table).table
    form = GaeDbManager(form_table).table
    logging.info('Updating project info for %s' % form_table)
    #get forms without project number
    q = form.all().filter('project_number = ', None)
    batch = []
    missing_list = []
    for t in q:
        p = get_project(t.project_key)
        if p:
            for fld in 'project_name project_number client_name'.split():
                setattr(t, fld, p[fld])
        else:
            msg = 'Project Information not found in dlz_project_list: %s' % (t.project_key)
            logging.warning(msg)
            missing_list.append(msg)
            
        batch.append(t)
    db.put(batch)
    email_notify('ymeng@dlz.com', 'Missing Project', '\n  '.join(missing_list))
    logging.info('Projects in %s is updated' % form_table)
    #update the test form
    logging.info('Populating project info for %s' % test_table)
    q = test.all().filter('project_number = ', None).order('PARENT_RECORD_ID')
    batch = []
    forms = {}
    for t in q:
        form_id = t.PARENT_RECORD_ID
        if forms.get(form_id):
            form_record = forms[form_id]
        else:
            q2 = form.all().filter('ID = ', form_id)
            for f in q2.fetch(1):
                record = {}
                if f.project_number:
                    for fld in 'project_name project_number client_name nuclear_no ds1 ds2 tested_by ms model form_date'.split():
                        record[fld] = getattr(f, fld)
                    forms[form_id] = record
                else:
                    logging.warning('project info is not found in the form table for ID=%s' % t.ID)
        
        if forms.get(form_id):
            for k, v in forms[form_id].items():
                setattr(t, k, v)
                batch.append(t)
                if len(batch)>100:
                    db.put(batch)
                    batch = []
    db.put(batch)
    logging.info('updates saved.')
    

def update_project_info(project_num):
    for table_name in ['compaction_test', 'compaction_form', 'asphalt_test', 'asphalt_form']:
        try:
            project_info_from_project_list(table_name, project_num)
        except:
            logging.warning('Failed to update project : %s for table %s' % (project_num, table_name))
    

def sync_all():
    q = model.dlz_connection.all()
    for t in q:
        if t.iform_page_id:
            sm = SyncManager(t.gae_table_name)
            sm.sync()
            
    #update project information
    try:
        populate_project_info('compaction_test', 'compaction_form')
    except:
        logging.warning('Failed to populate compaction project info')
    try:
        populate_project_info('asphalt_test', 'asphalt_form')
    except:
        logging.warning('Failed to populate asphalt project info')


def log_transaction(table, status, description):
    t = model.IformDatabaseLog()
    t.table = table
    t.status = status
    t.description = description
    t.put()
    

def run_failed_sync():
    for t in model.IformDatabaseLog.all().filter('status = ', 'new'):
        sm = SyncManager(t.table)
        sm.sync()
        t.status = 'complete'
    
class SyncManager(object):
    def __init__(self, table_name, description=None):
        self.table_name = table_name
        self.description = description
        q = model.dlz_connection.all().filter('gae_table_name = ', table_name)
        for r in q:
            self.iform_page_id = r.iform_page_id
            self.iform_table_name = r.iform_table_name
            self.gae_table_name = r.gae_table_name
    def _download(self, username=None, password=None, since_id=None, record_id=None, qtype=None):
        #def download_table(username, password,page_id, table_name, record_id=None, since_id=None, qtype=None ):
        '''download a table and return a json'''
        if username is None:
            username = dc.get('IFORM_USER')
        if password is None:
            password = dc.get('IFORM_PASSWORD')
    
        form_fields = {
          "USERNAME": username,
          "PASSWORD": password,
          'PAGE_ID': self.iform_page_id,
          'TABLE_NAME': self.iform_table_name,
          'TYPE': 'TOP'
        }
        if since_id:
            form_fields['SINCE_ID'] = since_id
        if record_id:
            form_fields['ID'] = record_id
        if qtype:
            form_fields['TYPE'] = qtype
            
        url = dc.get('IFORM_URL')
        logging.info('Downloading data from iFormBuilder: %s, %s' % (self.iform_page_id, self.table_name))
        logging.info('since_id = %s' % since_id)
        form_data = urllib.urlencode(form_fields)
        logging.info('url: %s' % url)
        logging.info('params posted:%s' % str(form_data))
        result = urlfetch.fetch(url=url,
                        payload=form_data,
                        method=urlfetch.POST)
        logging.info(result.content)
        data = simplejson.loads(result.content)
        logging.info('data downloaded: %s' % str(data)[:100])
        return data
    def sync(self, since_id=None):
        '''sync a table'''
        logging.info('sync data from iform table: %s' % self.table_name)
        gdm = GaeDbManager(self.table_name)
        
        if since_id is None:
            #query the largest ID
            q = gdm.table.all().order('-ID')
            result = q.fetch(1)
            if result:
                since_id = result[0].ID
            else:
                since_id = 0
        try:
            json = self._download(None, None, since_id, None, None)
            gdm.insert_iformjson(json)
            log_transaction(self.table_name, 'complete', self.description)
        except:
            log_transaction(self.table_name, 'new', self.description)
            logging.warning('Failed to sync table %s:', self.table_name)
        
        
